/* Copyright (c) 2009 Mark L. Howison
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  (1) Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *  (2) Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *  (3) The name of the copyright holder may not be used to endorse or promote
 *      products derived from this software without specific prior written
 *      permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package edu.berkeley.edrl.wiikinemathics;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

class NumberOption extends JPanel {

    private JLabel label;
    private JComboBox combo;
    private int start;
    private String[] vals;

    public NumberOption(String name, int val, int start, int stop) {
        int len = stop - start + 1;
        vals = new String[len];
        for (int i=0; i<len; i++) {
            vals[i] = new String(String.valueOf(start + i));
        }
        label = new JLabel(name);
        combo = new JComboBox(vals);
        combo.setSelectedIndex(val - start);
        add(label);
        add(combo);
    }
    
    public int getValue() {
        return start + combo.getSelectedIndex() + 1;
    }
}

class TextOption extends JPanel {

    private JLabel label;
    private JComboBox combo;

    public TextOption(String name, String[] vals) {
        label = new JLabel(name);
        combo = new JComboBox(vals);
        add(label);
        add(combo);
    }

    public boolean isSelected(Object obj) {
        return (combo.getSelectedItem() == obj);
    }

    public Object getSelected() {
        return combo.getSelectedItem();
    }
}

class Slider extends JPanel {

    JSlider slider;
    JLabel label;

    public Slider(String name, int val, int min, int max, int spacing) {

        slider = new JSlider(min, max, val);
        label = new JLabel();
        
        label.setFont(new Font("Monospaced", getFont().getStyle(), getFont().getSize()));
        label.setText(String.format("%6d", val));
        label.setLabelFor(slider);
        
        slider.setMajorTickSpacing(spacing);
        slider.setPaintTicks(true);
        slider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent evt) {
                JSlider slider = (JSlider)evt.getSource();
                label.setText(String.format("%6d", slider.getValue()));
                WiiKinemathicsApp.getApplication().motionPanel.repaint();
            }
        });

        setBorder(BorderFactory.createTitledBorder(name));
        add(label);
        add(slider);
    }

    public void setValue(int value) {
        slider.setValue(value);
    }

    public double getValue() {
        return (double)slider.getValue();
    }

    public int getInt() {
        return slider.getValue();
    }

    public double getNormValue() {
        return (double)slider.getValue() / (double)slider.getMaximum();
    }
}

/**
 *
 * @author mhowison
 */
public class ControlPanel extends JPanel {

    public final static String TARGET_ON = "On";
    public final static String TARGET_FADE = "Fade";
    public final static String TARGET_OFF = "Off";

    public final static String TRACKER_CROSSHAIRS = "Crosshairs";
    public final static String TRACKER_ACCURACY = "Accuracy";
    public final static String TRACKER_HEIGHT = "Height";
    public final static String TRACKER_RATIO = "Ratio";
    public final static String TRACKER_OFF = "Off";

    public final static String TRIAL_TIMED = "Timed";
    public final static String TRIAL_FREEFORM = "Freeform";

    public final static String HEIGHTLINE_TARGET = "Target";
    public final static String HEIGHTLINE_TRACKER = "Tracker";
    public final static String HEIGHTLINE_BOTH = "Both";

    private final static ChangeListener repaintListener = new ChangeListener()
    {
        public void stateChanged(ChangeEvent evt) {
            WiiKinemathicsApp.getApplication().motionPanel.repaint();
        }
    };

    private JPanel options;
    private JPanel sliders;
    
    JLabel connectLabel;
    TextOption trialOption;
    JButton reconnectButton;
    JButton startButton;
    JButton previewButton;
    JButton abortButton;
    JCheckBox pauseCheckBox;

    NumberOption rightValue;
    NumberOption leftValue;
    TextOption rTargetOption;
    TextOption lTargetOption;
    TextOption rTrackerOption;
    TextOption lTrackerOption;
    TextOption heightlineOption;
    JCheckBox backgroundOption;
    JCheckBox monotoneOption;
    JCheckBox constantDriverOption;
    JCheckBox downwardOption;
    JCheckBox yTicsOption;
    JCheckBox roundDriverOption;

    Slider heightSlider;
    Slider timeSlider;
    Slider toleranceSlider;
    Slider gridSlider;
    Slider unitsSlider;
    Slider backgroundSlider;

    /** Creates new form ControlPanel */
    public ControlPanel() {

        options = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();

        sliders = new JPanel();
        sliders.setLayout(new BoxLayout(sliders, BoxLayout.PAGE_AXIS));

        connectLabel = new JLabel();
        connectLabel.setText("[Disconnected]");
        connectLabel.setForeground(Color.RED);
        c.gridx = 0;
        c.gridy = 0;
        c.anchor = GridBagConstraints.LINE_START;
        options.add(connectLabel, c);

        String[] trialVals = { TRIAL_TIMED, TRIAL_FREEFORM };
        trialOption = new TextOption("Trial Mode", trialVals);
        c.gridx = 1;
        options.add(trialOption, c);

        reconnectButton = new JButton("Reconnect");
        reconnectButton.addActionListener(new ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                WiiKinemathicsApp.getApplication().connect();
            }
        });
        c.gridx = 0;
        c.gridy++;
        options.add(reconnectButton, c);

        startButton = new JButton("Start");
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                WiiKinemathicsApp.getApplication().start();
            }
        });
        c.gridx = 1;
        options.add(startButton, c);

        abortButton = new JButton("Abort");
        abortButton.addActionListener(new ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                WiiKinemathicsApp.getApplication().abort();
            }
        });
        c.gridx = 0;
        c.gridy++;
        options.add(abortButton, c);

        previewButton = new JButton("Preview");
        previewButton.addActionListener(new ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                WiiKinemathicsApp.getApplication().preview();
            }
        });
        c.gridx = 1;
        options.add(previewButton, c);

        pauseCheckBox = new JCheckBox("Pause");
        pauseCheckBox.setSelected(false);
        c.gridx = 0;
        c.gridy++;
        options.add(pauseCheckBox, c);

        leftValue = new NumberOption("Left Value",2,1,10);
        c.gridx = 0;
        c.gridy++;
        options.add(leftValue, c);

        rightValue = new NumberOption("Right Value",3,1,10);
        c.gridx = 1;
        options.add(rightValue, c);

        String[] targetVals = { TARGET_ON, TARGET_FADE, TARGET_OFF };

        lTargetOption = new TextOption("Left Target", targetVals);
        c.gridx = 0;
        c.gridy++;
        options.add(lTargetOption, c);

        rTargetOption = new TextOption("Right Target", targetVals);
        c.gridx = 1;
        options.add(rTargetOption, c);        

        String[] trackerVals = { TRACKER_CROSSHAIRS, TRACKER_ACCURACY, TRACKER_HEIGHT, TRACKER_RATIO, TRACKER_OFF };

        lTrackerOption = new TextOption("Left Tracker", trackerVals);
        c.gridx = 0;
        c.gridy++;
        options.add(lTrackerOption, c);

        rTrackerOption = new TextOption("Right Tracker", trackerVals);
        c.gridx = 1;
        options.add(rTrackerOption, c);

        String[] heightlineVals = { HEIGHTLINE_TARGET, HEIGHTLINE_TRACKER, HEIGHTLINE_BOTH };
        heightlineOption = new TextOption("Heightlines", heightlineVals);
        c.gridx = 0;
        c.gridy++;
        options.add(heightlineOption, c);

        backgroundOption = new JCheckBox("Background Color");
        backgroundOption.setSelected(false);
        c.gridx = 0;
        c.gridy++;
        options.add(backgroundOption, c);

        monotoneOption = new JCheckBox("Monotone Increasing");
        monotoneOption.setSelected(false);
        c.gridx = 1;
        options.add(monotoneOption, c);

        constantDriverOption = new JCheckBox("Constant Driver");
        constantDriverOption.setSelected(false);
        c.gridx = 0;
        c.gridy++;
        options.add(constantDriverOption, c);

        downwardOption = new JCheckBox("Downward Motion");
        downwardOption.setSelected(false);
        c.gridx = 1;
        options.add(downwardOption, c);

        yTicsOption = new JCheckBox("Show Y Tics");
        yTicsOption.setSelected(false);
        yTicsOption.addChangeListener(repaintListener);
        c.gridx = 0;
        c.gridy++;
        options.add(yTicsOption, c);

        roundDriverOption = new JCheckBox("Round Driver Input");
        roundDriverOption.setSelected(false);
        c.gridx = 1;
        options.add(roundDriverOption, c);

        heightSlider = new Slider("Tracker Height", 8, 1, 10, 1);
        timeSlider = new Slider("Time (ms)", 4000, 10, 10000, 1000);
        toleranceSlider = new Slider("Tolerance (%)", 10, 1, 20, 1);
        gridSlider = new Slider("Grid/Background Opacity", 1, 0, 10, 1);
        unitsSlider = new Slider("Grid Units", 10, 1, 100, 10);
        backgroundSlider = new Slider("Background Opacity", 8, 0, 10, 1);
        
        sliders.add(heightSlider);
        sliders.add(timeSlider);
        sliders.add(toleranceSlider);
        sliders.add(gridSlider);
        sliders.add(unitsSlider);
        sliders.add(backgroundSlider);

        add(options);
        add(sliders);
        setBorder(BorderFactory.createTitledBorder("Controls"));
        //setPreferredSize(new Dimension(640,480));
    }

    public void enableControls(boolean state) {
        reconnectButton.setEnabled(state);
        startButton.setEnabled(state);
        previewButton.setEnabled(state);
    }

    public double getRatio() {
        return (double)leftValue.getValue() / (double)rightValue.getValue();
    }
}